package com.test.wog.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.test.wog.bean.Node;
import com.test.wog.bean.RegularBus;
import com.test.wog.bean.Route;
import com.test.wog.dao.NodeDAO;
import com.test.wog.dao.RegularBusDAO;
import com.test.wog.dao.RouteDAO;
import com.test.wog.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

/**
 * 路径规划服务层
 *
 * @author linxun @buaa.edu.cn
 * @since 2020-01-30
 * @see Route
 * @see RouteDAO
 */
@Service
public class RouteService {
    @Autowired
    RouteDAO routeDAO;
    @Autowired
    RegularBusDAO regularBusDAO;
    @Autowired
    NodeDAO nodeDAO;
    @Autowired
    DateUtil du;
    final static double eps = 1e-6;//经纬度精度阈值

    /**
     * Gets final route.
     *
     * @param sName the s name
     * @param eName the e name
     * @param sTime the s time
     * @param type  the type
     * @return the final route
     * @throws ParseException the parse exception
     */
    public String getFinalRoute(String sName, String eName, String sTime, String type) throws ParseException {
        Node sNode = new Node();
        try{
            sNode = nodeDAO.getNodeByName(sName).get(0);
        }catch (Exception e){//如果数据库中找不到名称对应的POI，则用高德API找
            sNode = nodeDAO.getNodeByNameFromAmap(sName).get(0);
        }
        String loc[] = sNode.getGeom().split(" ");
        return getFinalRoute(Double.parseDouble(loc[0]), Double.parseDouble(loc[1]), eName, sTime, type);
    }


    /**
     * Gets final route.
     *
     * @param sLon  the s lon
     * @param sLat  the s lat
     * @param eName the e name
     * @param sTime the s time
     * @param type  the type
     * @return the final route
     * @throws ParseException the parse exception
     */
    public String getFinalRoute(double sLon, double sLat, String eName, String sTime, String type) throws ParseException {
        //目前仅考虑从XXX至场馆
        Node eNode = nodeDAO.getNodeByName(eName).get(0); //终点
        RegularBus regularBus = regularBusDAO.getRegularBusByDestType(eNode.getId(), type).get(0);
        Node regularBusSNode = nodeDAO.getNodeByID(regularBus.getOrigin());//班车起点=公交步行终点
        String regularBusSLoc[] = regularBusSNode.getGeom().split(" ");
        /*根据传入的起点坐标和根据终点名称推算出的步行+公交终点（班车起点）规划路径*/
        List<Route> routeList = getRouteByLocAndTime(sLon, sLat,
                Double.parseDouble(regularBusSLoc[0]), Double.parseDouble(regularBusSLoc[1]), sTime);
        String regularBusSTime = du.getDateTimeAfterSecond(sTime,  - regularBus.getDuration());//班车最晚出发时间
        System.out.println(regularBusSTime + " " + sTime + " " + regularBus.getDuration());
        Route regularBusRoute = getRegularBusRoute(regularBus, regularBusSTime);
        regularBusRoute = regularBusRoute.toBuilder()
                .eName(eName)
                .sName(regularBusSNode.getName())
                .desc("乘坐班车从" + regularBusSNode.getName() + "至" + eName)
                .duration(regularBus.getDuration())
                .length(regularBus.getLength())
                .build();
        routeList.add(regularBusRoute);
        String sName = "";
        Node sNode = nodeDAO.getNodeByLoc(sLon, sLat).get(0); //起点
        String sNodeLoc[] = sNode.getGeom().split(" ");//最近的关键点的坐标
        if(Math.abs(Double.parseDouble(sNodeLoc[0]) - sLon) < eps && Math.abs(Double.parseDouble(sNodeLoc[1]) - sLat) < eps){
            sName = sNode.getName();
        }
        else{
            //如果与所有关键节点的距离都非常远，那么直接从高德API获取经纬度对应位置
            sName = nodeDAO.getNodeByLocFromAmap(sLon, sLat).get(0).getName();
        }
        //转换成更规范的JSON
        JSONObject jo = new JSONObject();
        jo.put("origin", sName);
        jo.put("destination", eName);
        jo.put("route", routeList);
        return JSONObject.toJSONString(jo, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
    }

    /**
     * Get regular bus route route.
     *
     * @param regularBus the regular bus
     * @param sTime      the s time
     * @return the route
     */
    public Route getRegularBusRoute(RegularBus regularBus, String sTime){//根据班车信息和最晚出发时间获取班车路线
        System.out.println(regularBus.getId() + " " + sTime);
        RegularBus regularBusDesc = regularBusDAO.getRegularBusByIdAndTime(regularBus.getId(), sTime).get(0);
        Route route = Route.builder()
                .geom(regularBus.getGeom())
                .transType("班车")
                .sTime(regularBusDesc.getStart_time())
                .build();
        return route;
    }

    /**
     * Get route by loc and time list.
     *
     * @param sLon  the s lon
     * @param sLat  the s lat
     * @param eLon  the e lon
     * @param eLat  the e lat
     * @param sTime the s time
     * @return the list
     */
    public List<Route> getRouteByLocAndTime(double sLon, double sLat, double eLon, double eLat, String sTime){//将高德地图API获取的步行+公交json转化为Route的List
        List<Route> routeList = new ArrayList<>();
        JSONObject jo = routeDAO.getRouteFromAmapByLoc(sLon, sLat, eLon, eLat, sTime);
        JSONObject routePlan = jo.getJSONObject("route").getJSONArray("transits").getJSONObject(0);
        JSONArray routeArray = routePlan.getJSONArray("segments");
        for (int i = 0; i < routeArray.size(); i++) {
            JSONObject segJo = routeArray.getJSONObject(i);
            //转换步行部分
            JSONObject walkingSeg = segJo.getJSONObject("walking");
            double durationPerMeter = walkingSeg.getDouble("duration") / walkingSeg.getDouble("distance");//每秒钟走多少米
            JSONArray walkingArray = walkingSeg.getJSONArray("steps");
            for (int j = 0; j < walkingArray.size(); j++) {
                JSONObject curWalkingSeg = walkingArray.getJSONObject(j);
                Route walkingRoute = Route.builder()
                        .geom(curWalkingSeg.getString("polyline"))
                        .duration(durationPerMeter * curWalkingSeg.getDouble("distance"))
                        .length(curWalkingSeg.getDouble("distance"))
                        .transType("步行")
                        .desc(curWalkingSeg.getString("instruction"))
                        .eName(curWalkingSeg.getString("assistant_action"))
                        .build();
                routeList.add(walkingRoute);
            }
            //转换公交部分
            JSONArray busArray = segJo.getJSONObject("bus").getJSONArray("buslines");
            for (int j = 0; j < busArray.size(); j++) {
                JSONObject curBusSeg = busArray.getJSONObject(j);

                Route busRoute = Route.builder()
                        .geom(curBusSeg.getString("polyline"))
                        .duration(curBusSeg.getDouble("duration"))
                        .length(curBusSeg.getDouble("distance"))
                        .transType("公交")
                        .desc(curBusSeg.getString("name"))
                        .sName(curBusSeg.getJSONObject("departure_stop").getString("name"))
                        .eName(curBusSeg.getJSONObject("arrival_stop").getString("name"))
                        .build();
                /*根据起点站和终点站获取路径描述*/
                String routeDesc = "乘坐" + curBusSeg.getString("name")
                        + "从" + busRoute.getSName()
                        + "至" + busRoute.getEName();
                busRoute.setDesc(routeDesc);
                /*获取途径站*/
                JSONArray viaStopArray = curBusSeg.getJSONArray("via_stops");
                List<String> viaStopList = new ArrayList<>();
                for (int k = 0; k < viaStopArray.size(); k++) {
                    viaStopList.add(viaStopArray.getJSONObject(k).getString("name"));
                }
                busRoute.setViaName(viaStopList);
                routeList.add(busRoute);
            }
        }
        //System.out.println(jo.toString());
        /*将geom字段转换为数据库中类似的形式*/
        for (Route route : routeList) {
            String geom = route.getGeom();
            geom = geom.replace(",", " ").replace(";", ",");
            route.setGeom(geom);
        }
        return routeList;
    }
}
